/**
 * 
 */
package adnotatio.common.xml;

/**
 * This is a simple wrapper for XML documents used in XML utility methods on the
 * client and the server. This abstract class can be realized based on various
 * XML implementations (GWT, XML DOM, ...).
 * 
 * @author kotelnikov
 */
public abstract class XMLDocument {

    /**
     * The real wrapped XML node
     */
    private final Object fNode;

    /**
     * This constructor initializes the internal document
     * 
     * @param node the XML object corresponding to this document
     */
    public XMLDocument(Object node) {
        fNode = node;
    }

    /**
     * Returns a new element with the given name.
     * 
     * @param doc the node corresponding to the internal XML document
     * @param name the name of the node to created
     * @return a new element with the given name
     */
    protected abstract XMLElement createElement(Object doc, XMLName name);

    /**
     * Returns a newly created element corresponding to the specified name.
     * 
     * @param name the name of the element to create
     * @return a newly created element corresponding to the specified name
     */
    public final XMLElement createElement(XMLName name) {
        return createElement(fNode, name);
    }

    /**
     * Creates and returns a XML text object.
     * 
     * @param doc the parent node
     * @param content the content of a new text node to create
     * @return a newly created text node
     */
    protected abstract XMLText createTextNode(Object doc, String content);

    /**
     * Creates and returns a new text node.
     * 
     * @param content the content of a new text node to create
     * @return a newly created text node
     */
    public final XMLText createTextNode(String content) {
        return createTextNode(fNode, content);
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof XMLDocument))
            return false;
        XMLDocument e = (XMLDocument) obj;
        return fNode.equals(e.fNode);
    }

    /**
     * Returns the root element of this document
     * 
     * @return the root element of this document
     */
    public XMLElement getRootElement() {
        return getRootElement(fNode);
    }

    /**
     * Returns the XML node corresponding to the root of the given document.
     * 
     * @param doc the internal XML document for which the current root document
     *        should be returned
     * @return the XML node corresponding to the root of the given document
     */
    protected abstract XMLElement getRootElement(Object doc);

    /**
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        return fNode.hashCode();
    }

    /**
     * Sets the node child as a child for the first element
     * 
     * @param doc the document object
     * @param root the root element
     */
    protected abstract void setRootElement(Object doc, Object root);

    /**
     * Sets a new root element for this document
     * 
     * @param root a new root element for this document to set
     */
    public final void setRootElement(XMLElement root) {
        if (root.fDocument != this)
            throw new RuntimeException("Bad root element: "
                + "it was created with an another document.");
        setRootElement(fNode, root.fNode);
    }

    /**
     * @see java.lang.Object#toString()
     */
    public String toString() {
        return fNode.toString();
    }

}
